package cn.yomigaeri.warn.service.impl;

import cn.yomigaeri.common.entity.dto.WarnDTO;
import cn.yomigaeri.common.entity.vo.WarnVO;
import cn.yomigaeri.common.entity.dto.SignalDTO;
import cn.yomigaeri.common.entity.po.Rule;
import cn.yomigaeri.warn.client.SignalClient;
import cn.yomigaeri.warn.mapper.CarMapper;
import cn.yomigaeri.warn.producer.WarnProducer;
import cn.yomigaeri.warn.service.RuleService;
import cn.yomigaeri.warn.service.WarnSignalService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @ClassName: WarnSignalServiceImpl
 * @Package: cn.yomigaeri.warn.service.impl
 * @Description:
 * @Author Yomigaeri
 * @Create 2025/6/5 00:59
 * @Version 1.0
 */
@Service
@RequiredArgsConstructor
public class WarnSignalServiceImpl implements WarnSignalService {
    private final SignalClient signalClient;
    private final CarMapper carMapper;
    private final RuleService ruleService;
    private final StringRedisTemplate stringRedisTemplate;
    private final WarnProducer warnProducer;

    @Override
    public WarnVO warnSignal(List<SignalDTO> SignalDTOList) {
        List<WarnDTO> warns = new ArrayList<>();
        for (SignalDTO signalDTO : SignalDTOList) {
            //1. 调用upload微服务的uploadSignal方法
            signalClient.uploadSignal(signalDTO);
            //2. 调用upload服务的getSignal方法
            List<SignalDTO> signals = signalClient.getSignal(signalDTO.getCarId()).getData().getSignals();
            for (SignalDTO signal : signals) {
                WarnDTO warnDTO = checkSignal(signal);
                if (warnDTO != null) {
                    warns.add(warnDTO);
                }
            }
        }
        return !warns.isEmpty() ? new WarnVO(warns) : null;
    }

    public WarnDTO checkSignal(SignalDTO signal) {
        // 通过caffeine生成Rule列表
        List<Rule> rules = ruleService.getAllRulesWithCache();

        //1. 查询当前信号的车辆信息
        String key = "BatteryTypeOfCarId:" + signal.getCarId();
        if (!stringRedisTemplate.hasKey(key)) {
            stringRedisTemplate.opsForValue().set(key, carMapper.selectById(signal.getCarId()).getBatteryType().toString());
        }
        Integer batteryType = Integer.parseInt(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(key)));
//            Car car = carMapper.selectById(signal.getCarId());

        //2. 根据车辆电池类型和warnId在caffeine报警规则
        Rule rule = null;
        for (Rule value : rules)
            if (Objects.equals(value.getWarnId(), signal.getWarnId()) && Objects.equals(value.getBatteryType(), batteryType)) {
                rule = value;
                break;
            }
//            Rule rule = ruleMapper.selectByBatteryAndWarnId(car.getBatteryType(), signal.getWarnId());

        //3. 解析预警规则
        if (rule != null) {
            BigDecimal subtract;
            if ("M".equalsIgnoreCase(rule.getDifference())) {
                if (signal.getMx() == null || signal.getMi() == null) subtract = BigDecimal.valueOf(0);
                else subtract = signal.getMx().subtract(signal.getMi());
            } else if ("I".equalsIgnoreCase(rule.getDifference())) {
                if (signal.getIx() == null || signal.getIi() == null) subtract = BigDecimal.valueOf(0);
                else subtract = signal.getIx().subtract(signal.getIi());
            } else return null;
            String[] limit = rule.getWarnRule().split(",");
            // 快速判断是否预警
            if (subtract.compareTo(new BigDecimal(limit[limit.length - 1])) < 0) return null;
            for (int i = 0; i < limit.length; i++) {
                if (subtract.compareTo(new BigDecimal(limit[i])) >= 0) {
                    WarnDTO warnDTO = new WarnDTO();
                    warnDTO.setCarId(signal.getCarId());
                    warnDTO.setBatteryType(batteryType);
                    warnDTO.setWarnName(rule.getWarnName());
                    warnDTO.setWarnLevel(i);
                    warnDTO.setCreateTime(signal.getCreateTime());
                    //TODO 发送消息存入数据库中
                    warnProducer.sendSaveMessage(warnDTO);
                    return warnDTO;
                }
            }
        }
        return null;
    }

}

